package com.cgs.query.client.connection

import com.cgs.query.connection.ConnectionFactory
import com.cgs.query.domain.QuerySource
import com.cgs.query.exception.QueryException
import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import mu.KotlinLogging
import java.sql.Connection

private val logger = KotlinLogging.logger { }

class ClientPoolConnectionFactory : ConnectionFactory {

    private val sourceId2DataSource = hashMapOf<String, HikariDataSource>()

    override fun getConnection(projectName: String): Connection {
        TODO()
    }

    override fun getConnection(querySource: QuerySource): Connection {
        val dataSource = sourceId2DataSource[querySource.id] ?: throw QueryException("本地没有该数据源")
        return if (querySource.jdbcEquals(dataSource))
            dataSource.connection
        else
            throw QueryException("本地存在类似数据源,但不一致")
    }

    override fun returnConnection(conn: Connection) = conn.close()

    fun registryDataSource(querySource: QuerySource) {
        sourceId2DataSource[querySource.id] = querySource.hikariBuild()
    }

    fun changedAndRegistry(querySource: QuerySource?) {
        if (querySource != null) {
            val localDataSource = sourceId2DataSource[querySource.id]
            if (localDataSource != null) {
                if (!querySource.jdbcEquals(localDataSource)) {
                    logger.info { "服务端数据源已经改变,客户端跟随改变" }
                    registryDataSource(querySource)
                }
            }
        }
    }
}

fun QuerySource.hikariBuild(): HikariDataSource {

    return HikariDataSource(HikariConfig().also {
        it.jdbcUrl = this.url
        it.username = this.userName
        it.password = this.password
        it.maximumPoolSize = this.maxPoolSize
        it.connectionTimeout = this.timeout
        it.idleTimeout = this.idleTimeout
        it.maxLifetime = this.maxLifetime
        logger.info { "Build HikariDataSource:[$name]" }
    })
}

fun QuerySource.jdbcEquals(dataSource: HikariDataSource): Boolean {
    return this.url == dataSource.jdbcUrl && this.userName == dataSource.username
            && this.password == dataSource.password
}
